/******************************************************************************************
 * Import
 ******************************************************************************************/

// module
import _ from 'lodash';

// project
import Indicator from './http/indicator';
import Collect from './http/collect';
import Param from './http/param';
import Parse from './http/parse';

/******************************************************************************************
 * Export Class
 ******************************************************************************************/

/**
 * 请求设置对象结构：
 * {
 *      url: string,                    // url地址,
 *      data: object,                   // 参数键值对,
 *      success(data)=> {},             // 成功回调函数
 *      error(err)=> {}                 // 逻辑错误回调函数
 *      config: {                       // 设置对象
 *          debug: boolean,             // 是否在console中追踪response，（默认为false）
 *          parse: '',                  // 解析器设置，可选择已经在库中存在的解析器，默认为hesq
 *          header: object,             // 需要携带的header对象
 *          indicator: {                // 指示器（吐司菜单）对象（发送http请求时显示，完成http请求时隐藏）
 *              start() {},             // 开始执行动作回调
 *              end() {}                // 结束执行动作回调
 *          },
 *          fail: {                     // 失败对象，对服务端错误、网络错误的统一处理
 *              status(res, obj) {},    // 服务器状态错误处理器
 *              parse(text, obj) {},    // 返回值解析错误处理器
 *              format(text, obj) {},   // 返回值的格式错误处理器
 *              network(err) {}         // 网络错误处理器
 *          }
 *      } 
 * }
 */
export default class Http {

    /*------------------------------------------------------------------------------------
	 * 外部调用接口
	 *-----------------------------------------------------------------------------------*/
    /**
     * get请求，参数请看_request方法
     * 
     * @param {*} obj 访问请求设置对象 
     */
    static get(obj) {
        obj['method'] = 'GET';
        this.request(obj);
    }

    /**
     * post请求，参数请看_request方法
     * 
     * @param {*} obj 访问请求设置对象 
     */
    static post(obj) {
        obj['method'] = 'POST';
        this.request(obj);
    }

    /**
     * 真实访问方法
     * 
     * @param {*} method 访问方法
     * @param {*} obj 访问请求设置对象 
     */
    static request(obj) {

        // ------------------------------------------------------ 
        // 显示指示器
        Indicator.start(obj.indicator);

        // ------------------------------------------------------ 
        // 设置url（主要用于get）
        if (obj.method == 'GET') {
            obj.url = obj.url + Param.get(obj.url, obj.data);
        }
        
        // ------------------------------------------------------ 
        // 设置body（主要用于post）
        // 注：如果不需要添加body字段，则Param.post函数返回的是null
        if (obj.method == 'POST') {
            let result = Param.post(obj);
            if (result != null) {
                obj['body'] = result;
            }
        }

        // ------------------------------------------------------ 
        // 根据obj设置config。config是真正需要带入request的配置
        let config = { method: obj.method };
        if (obj.header) config['headers'] = obj.header;
        if (obj.body) config['body'] = obj.body;

        // ------------------------------------------------------ 
        // 发起请求，并返回数据
        // 会进行追踪，并判断是否存在服务器状态码错误，最后将文本类型的返回值交给下一步
        fetch(obj.url, config).then((res)=> {

            // 如果打开了debug，则输出response信息
            if (_.isObject(obj.config) && obj.config.debug) {
                console.log('--------- ' + obj.method + ' : ' + obj.url);
                if (_.isObject(obj.data)) {
                    console.log(obj.data);
                }
                console.log(res);
                console.log('--------- END');
            }

            // 返回码判断，如果不等于200，则：收集错误，调用错误回调，并直接返回
            if (parseInt(res.status) != 200) {
                Collect.statusFail(res, obj);
                if (_.isObject(obj.fail) && _.isFunction(obj.fail.status)) {
                    obj.fail.status(res, obj);
                }
                return null;
            }

            // 将数据返回给下一步，注意，这里全部返回为text类型
            return res.text(); 
        })

        // ------------------------------------------------------ 
        // 数据处理
        .then((text)=> {

            // 隐藏指示器
            Indicator.end(obj.indicator);

            // 空值判断，返回码不为200时，text为null，则直接返回
            if (text == null) {
                return;
            }
            
            // 赋值parse类型
            let parse = 'hesq';
            if (_.isObject(obj.config) && _.isString(obj.config.parse)) {
                parse = obj.config.parse;
            }

            // 执行解析
            Parse[parse].action(text, obj);
        })

        // ------------------------------------------------------ 
        // 错误抓取
        .catch((err) => {

            // 隐藏指示器
            Indicator.end(obj.indicator);

            // 收集错误，并调用错误回调
            Collect.networkFail(err, obj);
            if (_.isObject(obj.fail) && _.isFunction(obj.fail.network)) {
                obj.fail.network(err, obj);
            } 
        });
    }
}
